package com.orange.tool.test;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.xwpf.usermodel.IBodyElement;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import com.pomelo.Application;
import com.pomelo.base.core.util.CommonUtil;
import com.pomelo.base.core.util.DbUtil;
import com.pomelo.base.core.util.StringUtil;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@WebAppConfiguration
public class ZxbzReadWord {

    private static Log LOGGER = LogFactory.getLog(ZxbzReadWord.class);

    @Test
    public void readWord() {
        try {
            File file = new File("E:\\wisedu\\高校信息标准（基础代码）规范V6.0.docx");
            FileInputStream fis = new FileInputStream(file);
            XWPFDocument xdoc = new XWPFDocument(fis);
            Iterator<IBodyElement> iter = xdoc.getBodyElementsIterator();
            // ReadDto readDto = null;
            List<ReadDto> readDtos = new ArrayList<>();
            while (iter.hasNext()) {
                IBodyElement element = iter.next();
                if (element instanceof XWPFParagraph) {
                    XWPFParagraph paragraph = (XWPFParagraph) element;
                    String titleLvl = getTitleLvl(xdoc, paragraph);
                    if (StringUtils.isNotEmpty(titleLvl) && StringUtils.isNumeric(titleLvl)) {
                        ReadDto readDto = new ReadDto();
                        readXWPFParagraph(xdoc, paragraph, readDto);
                        readDtos.add(readDto);
                    } else {
                        if (readDtos.size() > 0) {
                            ReadDto readDto = readDtos.get(readDtos.size() - 1);
                            readXWPFParagraph(xdoc, paragraph, readDto);
                        }
                    }
                } else if (element instanceof XWPFTable) {
                    XWPFTable paragraph = (XWPFTable) element;
                    if (readDtos.size() > 0) {
                        ReadDto readDto = readDtos.get(readDtos.size() - 1);
                        readXWPFTable(xdoc, paragraph, readDto);
                    }
                }
            }
            readDtos.remove(0);
            readDtos.remove(0);
            setProp(readDtos);
            int i = 1;
            List<String> tables = new ArrayList<>();
            for (ReadDto dto : readDtos) {
                if (StringUtil.isEmpty(dto.getTableName())) {
                    continue;
                }
                if (tables.contains(dto.getTableName())) {
                    continue;
                } else {
                    tables.add(dto.getTableName());
                }
                Map<String, Object> data = new HashMap<>();
                data.put("NO_", dto.getNo());
                data.put("GROOUP_", dto.getGroup());
                data.put("TABLENAME_", dto.getTableName());
                data.put("DESCRIPTION_", dto.getDescription());
                data.put("SOURCE_", dto.getSource());
                data.put("COMMENT_", dto.getComment());
                data.put("ORDER_ID_", i);
                i++;
                DbUtil.saveOrUpdate("ORANGE_ZXBZ_LIST", data);
                String sql = dto.getSql();
                if (!StringUtil.isEmpty(sql)) {
                    DbUtil.execute(dto.getSql());
                    DbUtil.save(dto.getTableName(), dto.getDatas());
                }
                LOGGER.info("=========^^======" + dto.getTableName() + "===============");
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
        LOGGER.info("===============^-^结束^-^===============");
    }

    /**
     * 
     *
     * @param readDtos
     * @throws Exception
     */
    private static void setProp(List<ReadDto> readDtos) throws Exception {
        int zeroCount = 0;// 0出现的次数
        int oneCount = 0;// 1出现的次数
        int twoCount = 0;// 2出现的次数
        int threeCount = 0;// 3出现的次数
        int curPoint = 0;// 当前指针值
        String group = "";
        for (int i = 0; i < readDtos.size(); i++) {
            int curLevel = readDtos.get(i).getTitleLevel();
            ReadDto readDto = readDtos.get(i);
            if (curLevel > 4) {
                throw new RuntimeException("暂不支持目录层级超过4层!!!");
            }
            if (curPoint == 0) {
                zeroCount++;
                curPoint = 1;
                readDtos.get(i).setPrefix(zeroCount + ".");
            } else if (curPoint == 1) {
                if (curLevel == 0) {
                    zeroCount++;
                    oneCount = 0;
                    twoCount = 0;
                    threeCount = 0;
                    curPoint = 1;
                    readDtos.get(i).setPrefix(zeroCount + ".");
                }
                if (curLevel == 1) {
                    curPoint++;
                    oneCount++;
                    readDtos.get(i).setPrefix(zeroCount + "." + "1.");
                    group = readDto.getTitle();
                }
            } else if (curPoint == 2) {
                if (curLevel == 0) {
                    zeroCount++;
                    oneCount = 0;
                    twoCount = 0;
                    threeCount = 0;
                    curPoint = 1;
                    readDtos.get(i).setPrefix(zeroCount + ".");
                } else if (curLevel == 1) {
                    oneCount++;
                    twoCount = 0;
                    curPoint = 2;
                    readDtos.get(i).setPrefix(zeroCount + "." + oneCount + ".");
                } else if (curLevel == 2) {
                    curPoint = 3;
                    twoCount++;
                    threeCount = 0;
                    readDtos.get(i).setPrefix(zeroCount + "." + oneCount + "." + twoCount + ".");
                    readDto.setGroup(group);
                    readDto.setNo(oneCount + "." + twoCount);
                }
            } else if (curPoint == 3) {
                if (curLevel == 0) {
                    zeroCount++;
                    oneCount = 0;
                    twoCount = 0;
                    threeCount = 0;
                    curPoint = 1;
                    readDtos.get(i).setPrefix(zeroCount + ".");
                } else if (curLevel == 1) {
                    oneCount++;
                    curPoint = 2;
                    twoCount = 0;
                    readDtos.get(i).setPrefix(zeroCount + "." + oneCount + ".");
                } else if (curLevel == 2) {
                    curPoint = 3;
                    twoCount++;
                    threeCount = 0;
                    readDtos.get(i).setPrefix(zeroCount + "." + oneCount + "." + twoCount + ".");
                    readDto.setGroup(group);
                    readDto.setNo(oneCount + "." + twoCount);
                } else if (curLevel == 3) {
                    threeCount++;
                    if (i < readDtos.size() - 1) {
                        int nextLevel = readDtos.get(i + 1).getTitleLevel();
                        if (nextLevel > 3) {
                            throw new RuntimeException("暂不支持目录层级超过4层!!!");
                        }
                        if (nextLevel == 3) {
                            curPoint = 3;
                        } else if (nextLevel < 3) {
                            curPoint = nextLevel + 1;
                        }
                    }
                    readDtos.get(i).setPrefix(zeroCount + "." + oneCount + "." + twoCount + "." + threeCount + ".");
                }
            }
            if (readDto.getTitleLevel() == 2) {
                String title = readDto.getTitle().trim();
                int index1 = title.indexOf("（");
                int index2 = title.indexOf("(");
                String tableName = null;
                String description = null;
                if (index1 > 0 && index2 > 0) {
                    if (index1 < index2) {
                        String[] titleArray = title.split("（");
                        tableName = titleArray[0];
                        description = titleArray[1];
                        description = description.replaceAll("（", "").replaceAll("）", "");
                    } else {
                        String[] titleArray = title.split("\\(");
                        tableName = titleArray[0];
                        description = titleArray[1];
                        description = description.replaceAll("\\(", "").replaceAll("\\)", "");
                    }
                } else if (index1 > 0) {
                    String[] titleArray = title.split("（");
                    tableName = titleArray[0];
                    description = titleArray[1];
                    description = description.replaceAll("（", "").replaceAll("）", "");
                } else if (index2 > 0) {
                    String[] titleArray = title.split("\\(");
                    tableName = titleArray[0];
                    description = titleArray[1];
                    description = description.replaceAll("\\(", "").replaceAll("\\)", "");
                }
                readDto.setTableName(tableName);
                readDto.setDescription(description);
                convertData(readDto);
            }
        }
    }

    private static Map<String, String> mapping = new HashMap<>();

    static {
        mapping.put("代码", "DM");
        mapping.put("名称", "MC");
        mapping.put("层次", "CC");
        mapping.put("上级代码", "LS");
        mapping.put("隶属", "LS");
    }

    /**
     * 转换数据
     *
     * @param dto
     * @throws Exception
     */
    private static void convertData(ReadDto dto) throws Exception {
        List<List<Object>> rows = dto.getTableRows();
        if (!CommonUtil.isEmptyList(rows)) {
            List<Object> title = rows.get(0);
            List<Map<String, Object>> datas = new ArrayList<>();
            String[] titles = new String[title.size()];
            Map<String, String> newMapping = new HashMap<>();
            newMapping.putAll(mapping);
            String sql = "CREATE TABLE " + dto.getTableName()
                + "(WID VARCHAR2(40),DM VARCHAR2(100),MC VARCHAR2(300),PX NUMBER,SFSY VARCHAR2(10) ,LS VARCHAR2(100),CC VARCHAR2(10) ";
            int count = 0;
            for (int i = 0; i < title.size(); i++) {
                titles[i] = StringUtil.toStr(title.get(i)).trim();
                if (!newMapping.containsKey(titles[i])) {
                    String pym = getFirstPinYin(titles[i]).toUpperCase();
                    sql += "," + pym + " VARCHAR2(200) ";
                    newMapping.put(titles[i], pym);
                } else {
                    count++;
                }
            }
            sql += ")";
            if (count > 0) {
                dto.setSql(sql);
            } else {
                LOGGER.info("========未查询到表头==================" + dto.getTableName() + "============================");
            }
            for (int i = 1; i < rows.size(); i++) {
                Map<String, Object> data = new HashMap<>();
                data.put("SFSY", "1");
                List<Object> row = rows.get(i);
                for (int j = 0; j < titles.length; j++) {
                    data.put(newMapping.get(titles[j]), row.get(j));
                }
                data.put("WID", data.get("DM"));
                data.put("PX", i);
                datas.add(data);
            }
            dto.setDatas(datas);
        }
    }

    /**
     * 读取文本内容
     *
     * @param xdoc
     * @param paragraph
     * @param readDto
     * @throws Exception
     */
    private static void readXWPFParagraph(XWPFDocument xdoc, XWPFParagraph paragraph, ReadDto readDto)
        throws Exception {
        String text = paragraph.getText();
        String titleLvl = getTitleLvl(xdoc, paragraph);
        if (StringUtils.isNotEmpty(titleLvl) && StringUtils.isNumeric(titleLvl)) {
            int level = Integer.valueOf(titleLvl);
            readDto.setTitle(text);
            readDto.setTitleLevel(level);
        } else if (text.startsWith("【来源】")) {
            text = text.substring(4);
            text = text.replaceAll("：", "").replaceAll(":", "");
            readDto.setSource(text);
        } else if (text.startsWith("【备注】")) {
            text = text.substring(4);
            text = text.replaceAll("：", "").replaceAll(":", "");
            readDto.setComment(text);
        }
    }

    /**
     * 读取表格
     *
     * @param xdoc
     * @param table
     * @param readDto
     * @return
     * @throws Exception
     */
    private static void readXWPFTable(XWPFDocument xdoc, XWPFTable table, ReadDto readDto) throws Exception {
        List<XWPFTableRow> xwpfTableRows = table.getRows();
        List<List<Object>> datas = new ArrayList<>();
        for (XWPFTableRow xwpfTableRow : xwpfTableRows) {
            List<Object> data = new ArrayList<>();
            List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();
            for (XWPFTableCell xwpfTableCell : xwpfTableCells) {
                List<XWPFParagraph> xwpfParagraphs = xwpfTableCell.getParagraphs();
                XWPFParagraph xwpfParagraph = xwpfParagraphs.get(0);
                data.add(xwpfParagraph.getText());
            }
            datas.add(data);
        }
        readDto.setTableRows(datas);
    }

    /**
     * Word中的大纲级别，可以通过getPPr().getOutlineLvl()直接提取，但需要注意，Word中段落级别，通过如下三种方式定义：
     * 1、直接对段落进行定义；
     * 2、对段落的样式进行定义；
     * 3、对段落样式的基础样式进行定义。
     * 因此，在通过“getPPr().getOutlineLvl()”提取时，需要依次在如上三处读取。
     *
     * @param doc
     * @param para
     * @return
     */
    private static String getTitleLvl(XWPFDocument doc, XWPFParagraph para) throws Exception {
        String titleLvl = "";
        try {
            // 判断该段落是否设置了大纲级别
            if (para.getCTP().getPPr().getOutlineLvl() != null) {
                return String.valueOf(para.getCTP().getPPr().getOutlineLvl().getVal());
            }
        } catch (Exception e) {
        }
        try {
            // 判断该段落的样式是否设置了大纲级别
            if (doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl() != null) {
                return String
                    .valueOf(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
            }
        } catch (Exception e) {
        }
        try {
            // 判断该段落的样式的基础样式是否设置了大纲级别
            if (doc.getStyles().getStyle(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal())
                .getCTStyle().getPPr().getOutlineLvl() != null) {
                String styleName = doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal();
                return String
                    .valueOf(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
            }
        } catch (Exception e) {

        }
        try {
            if (para.getStyleID() != null) {
                return para.getStyleID();
            }
        } catch (Exception e) {

        }
        return titleLvl;
    }

    public static String getAllPinyin(String hanzi) {
        // 输出格式设置
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        /**
         * 输出大小写设置
         *
         * LOWERCASE:输出小写
         * UPPERCASE:输出大写
         */
        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);

        /**
         * 输出音标设置
         *
         * WITH_TONE_MARK:直接用音标符（必须设置WITH_U_UNICODE，否则会抛出异常）
         * WITH_TONE_NUMBER：1-4数字表示音标
         * WITHOUT_TONE：没有音标
         */
        format.setToneType(HanyuPinyinToneType.WITH_TONE_MARK);

        /**
         * 特殊音标ü设置
         *
         * WITH_V：用v表示ü
         * WITH_U_AND_COLON：用"u:"表示ü
         * WITH_U_UNICODE：直接用ü
         */
        format.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);

        char[] hanYuArr = hanzi.trim().toCharArray();
        StringBuilder pinYin = new StringBuilder();

        try {
            for (int i = 0, len = hanYuArr.length; i < len; i++) {
                // 匹配是否是汉字
                if (Character.toString(hanYuArr[i]).matches("[\\u4E00-\\u9FA5]+")) {
                    // 如果是多音字，返回多个拼音，这里只取第一个
                    String[] pys = PinyinHelper.toHanyuPinyinStringArray(hanYuArr[i], format);
                    pinYin.append(pys[0]).append(" ");
                } else {
                    pinYin.append(hanYuArr[i]).append(" ");
                }
            }
        } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
            badHanyuPinyinOutputFormatCombination.printStackTrace();
        }
        return pinYin.toString();
    }

    public static String getFirstPinYin(String hanyu) {
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

        StringBuilder firstPinyin = new StringBuilder();
        char[] hanyuArr = hanyu.trim().toCharArray();
        try {
            for (int i = 0, len = hanyuArr.length; i < len; i++) {
                if (Character.toString(hanyuArr[i]).matches("[\\u4E00-\\u9FA5]+")) {
                    String[] pys = PinyinHelper.toHanyuPinyinStringArray(hanyuArr[i], format);
                    firstPinyin.append(pys[0].charAt(0));
                } else {
                    firstPinyin.append(hanyuArr[i]);
                }
            }
        } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
            badHanyuPinyinOutputFormatCombination.printStackTrace();
        }
        return firstPinyin.toString();
    }

}

class ReadDto {

    private String prefix;

    private String title;

    private int titleLevel;

    private String source;

    private String comment;

    private String tableName;

    private String description;

    private String group;

    private String no;

    private List<List<Object>> tableRows;

    private List<Map<String, Object>> datas;

    private String sql;

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getTitleLevel() {
        return titleLevel;
    }

    public void setTitleLevel(int titleLevel) {
        this.titleLevel = titleLevel;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<List<Object>> getTableRows() {
        return tableRows;
    }

    public void setTableRows(List<List<Object>> tableRows) {
        this.tableRows = tableRows;
    }

    public String getGroup() {
        return group;
    }

    public void setGroup(String group) {
        this.group = group;
    }

    public String getNo() {
        return no;
    }

    public void setNo(String no) {
        this.no = no;
    }

    public List<Map<String, Object>> getDatas() {
        return datas;
    }

    public void setDatas(List<Map<String, Object>> datas) {
        this.datas = datas;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

}
